global comprimir_buffer
; int comprimir buffer ( 
	;	unsigned char *scr buf, 
	;	unsigned int scr size,
	; 	unsigned char **dst buf,
	; 	unsigned int *dst size,
	; 	codigo t **tabla codigos, 
	;	unsigned int *long codificacion
	;)
;  • Descripcion: Dado un buffer de entrada, comprime los datos contenidos en  el.
;    Devuelve el puntero al buffer con los datos comprimidos, la longitud de este buffer
;    en bytes, un puntero a la tabla de codigos utilizada para realizar la codificacion y
;    la longitud en bits de la codificacion. En caso de no poder realizar la compresion
;    debe retornar un codigo de error.

;
;• Funciones auxiliares que utiliza: generar tabla apariciones,
;  generar tabla codigos, calcular longitud codificacion,
;  generar codificacion.



extern printf
extern malloc
extern free
extern generar_tabla_codigos
extern calcular_longitud_codificacion
extern generar_codificacion
extern generar_tabla_apariciones

%define p_src_buf ebp+8
%define src_size ebp+12
%define pp_dst_buf ebp+16
%define p_dst_size ebp+20
%define pp_tabla_codigos ebp+24
%define p_long_codificacion ebp+28
%define p_tabla_apariciones ebp-4
%define null 0

section .data

msg_buffer_vacio: db 'El buffer de origen esta vacia.' ,10,0 ;
msg_codificacion_extensa: db 'ERROR: La codificacion a generar es demasiado extensa.' ,10,0 ;
msg_tabla_ap_vacia: db 'La tabla de apariciones esta vacia', 10, 0 ; 
error_en_generar_codificacion: db 'ERROR generando codificacion' ,10,0
msg_tabla_codigos_null:	db 'ERROR se recibio tabla de codigos null',10,0

section .text
comprimir_buffer: 
	;enter 4,0	comentado para probar con valgrind
	push ebp
	mov ebp,esp
	sub esp,4
	
	push esi
	push edi
	push ebx
	
	mov dword [p_tabla_apariciones], null	; inicializamos en 0 para liberar despues
	
	cmp dword [p_src_buf], null
	jne _buffer_ok
	jmp _bufferVacio
	
_buffer_ok:	
	push dword [src_size] ; falta pushear un parametro pero no se a que hace referencia.
	push dword [p_src_buf]
	call generar_tabla_apariciones
	add esp,8
	
	mov [p_tabla_apariciones],eax	; guardamos el puntero para liberar
	
	cmp eax,null
	jne _tabla_no_vacia ; tabla de apariciones vacia
	jmp _tabla_ap_vacia
	
_tabla_no_vacia:
	
	mov esi,eax ; en esi tengo el puntero a la tabla de apariciones generada.
	
	push esi
	call generar_tabla_codigos
	add esp,4
	
	; tengo en eax un puntero a una tabla de elementos de tipo codigo_t
	; con la tabla de codigos.
	
	cmp eax,null
	jne _tabla_codigos_no_null
	jmp _codigos_null
		
_tabla_codigos_no_null:

	mov edx, [pp_tabla_codigos] ; bajo en edx el puntero al puntero de la tabla de codigos.
	mov dword [edx],eax  ; guardo en memoria,  pisando el contenido del puntero pp_tabla_codigos con el puntero a la tabla de codigos.
	mov edx, eax  ; pongo el puntero de la tabla de codigos en edx
	
	push edx ; pusheo el puntero a la tabla de codigos
	push esi ; pusheo el puntero a la tabla de apariciones
	call calcular_longitud_codificacion
	add esp,8
	
	cmp eax,-1
	jne _codificacion_entra
	jmp _codificacion_extensa
	
_codificacion_entra:
	
	
	mov edi,[p_long_codificacion] ;
	mov [edi], eax  ; muevo a donde apunta p_long_codificacion el contenido de eax que es la long de la codif.
	mov edi,eax  ; en edi tengo la longitud de la codificación en bits.
	
	mov ebx, [pp_dst_buf] ; pongo en ebx el puntero al puntero del buffer de destino.
	
	mov ecx,[p_long_codificacion]
	mov [ecx], edi 		; escribimos en p_dst_size la longitud en bytes con exceso de 1

	add eax,32	; sumamos 32 bits porque escribimos de a 4 bytes en el buffer de salida.
			; Lo que no sobrá del buffer esta entre 0 y 32 bits.
	shr eax,3	; En eax ahora tenemos el tamaño en bytes
	mov ecx,[p_dst_size]
	mov [ecx], eax 		; escribimos en p_dst_size la longitud en bytes con exceso de 1
	
	mov ecx, eax ; en ecx tengo el tamanio en bytes del buffer de salida.
	
	push ecx	; Protegemos ecx porque malloc lo destruye
	push eax
	call malloc
	add esp,4
	pop ecx		; Restauramos ecx.
	; En eax tenemos un puntero al buffer destino.
	
	mov edx, [pp_tabla_codigos]	; la funcion toma un * no un **
	mov edx,[edx]
	
	mov ebx, [pp_dst_buf]     ; la funcion toma un * no un **
	mov [ebx], eax
	
	push edx ;  pusheo el puntero a la tabla de codigos.
	push edi ;  pusheo el tamanio del destino
	push eax ;  pusheo el puntero al buffer de destino
	push dword [src_size] ; pusheo el tamanio del buffer de origen
	push dword [p_src_buf] ; pusheo el puntero al buffer a comprimir, es decir, el buffer de origen.
	call generar_codificacion
	add esp,20
	
	cmp eax,-1
	
	je _error_en_generar_codificacion 
	
	xor eax,eax
	jmp fin
	
	
_error_en_generar_codificacion:
	push error_en_generar_codificacion 
	call printf
	add esp,4
	mov eax,-1
	jmp fin
	
_bufferVacio:
	push msg_buffer_vacio
	call printf
	add esp,4
	mov eax,-1	
	jmp fin
	

_tabla_ap_vacia:
	push msg_tabla_ap_vacia
	call printf
	add esp,4
	mov eax,-1
	jmp fin
	
_codificacion_extensa:
	push msg_codificacion_extensa
	call printf
	add esp,4
	mov eax,-1
	jmp fin
	
_codigos_null:
	push dword msg_tabla_codigos_null
	call printf
	add esp,4
	mov eax,-1
		
fin:
	mov edi, eax		;Protegemos el valor de retorno
	
	mov ebx, [p_tabla_apariciones]
	cmp ebx,null
	je _retornar
	
	push ebx
	call free		; liberamos la tabla de apariciones.	
	add esp,4
	
	mov eax,edi
	
_retornar:

	pop ebx
	pop edi
	pop esi
	leave
	ret
